/**
 * @file soap_message.cpp
 * @brief ONVIF SOAP消息处理实现
 * 
 * 本文件实现ONVIF协议的SOAP消息解析、生成和处理功能
 * 支持SOAP 1.2、WS-Security等标准
 */

#include "soap_message.h"
#include <sstream>
#include <regex>
#include <chrono>
#include <iomanip>

namespace El {
namespace Onvif {

// SoapMessageParser实现
SoapMessageParser::SoapMessageParser() = default;
SoapMessageParser::~SoapMessageParser() = default;

SoapMessage SoapMessageParser::ParseSoapRequest(const std::string& soapXml) const {
    SoapMessage message;
    
    try {
        // 解析SOAP Header
        message.header = ParseSoapHeader(soapXml);
        
        // 解析SOAP Body
        message.body = ParseSoapBody(soapXml);
        
        // 提取Action
        message.action = ExtractSoapAction(soapXml);
        
        // 检查WS-Security
        message.hasWSSecurity = CheckWSSecurity(soapXml);
        
        // 提取用户凭据
        if (message.hasWSSecurity) {
            auto credentials = ExtractCredentials(soapXml);
            message.username = credentials.first;
            message.password = credentials.second;
        }
        
    } catch (const std::exception& e) {
        // 解析失败，返回空消息
        message = SoapMessage{};
    }
    
    return message;
}

std::string SoapMessageParser::GenerateSoapResponse(const std::string& responseBody,
                                                   const std::string& /*action*/) const {
    std::ostringstream oss;
    
    oss << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
        << "<soap:Envelope xmlns:soap=\"http://www.w3.org/2003/05/soap-envelope\"\n"
        << "               xmlns:tds=\"http://www.onvif.org/ver10/device/wsdl\"\n"
        << "               xmlns:trt=\"http://www.onvif.org/ver10/media/wsdl\"\n"
        << "               xmlns:tptz=\"http://www.onvif.org/ver20/ptz/wsdl\"\n"
        << "               xmlns:tt=\"http://www.onvif.org/ver10/schema\">\n"
        << "  <soap:Header/>\n"
        << "  <soap:Body>\n"
        << responseBody
        << "  </soap:Body>\n"
        << "</soap:Envelope>\n";
    
    return oss.str();
}

std::string SoapMessageParser::GenerateSoapFault(SoapError error,
                                                const std::string& detail) const {
    std::string faultCode, faultString;
    
    switch (error) {
        case SoapError::InvalidMessage:
            faultCode = "soap:Sender";
            faultString = "Invalid SOAP message format";
            break;
        case SoapError::InvalidAction:
            faultCode = "soap:Sender"; 
            faultString = "Invalid SOAP action";
            break;
        case SoapError::AuthenticationFailed:
            faultCode = "soap:Sender";
            faultString = "Authentication failed";
            break;
        case SoapError::AuthorizationFailed:
            faultCode = "soap:Sender";
            faultString = "Authorization failed";
            break;
        case SoapError::InternalError:
            faultCode = "soap:Receiver";
            faultString = "Internal server error";
            break;
        case SoapError::NotSupported:
            faultCode = "soap:Sender";
            faultString = "Operation not supported";
            break;
        case SoapError::BadRequest:
            faultCode = "soap:Sender";
            faultString = "Bad request";
            break;
        default:
            faultCode = "soap:Receiver";
            faultString = "Unknown error";
            break;
    }
    
    std::ostringstream oss;
    oss << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
        << "<soap:Envelope xmlns:soap=\"http://www.w3.org/2003/05/soap-envelope\">\n"
        << "  <soap:Header/>\n"
        << "  <soap:Body>\n"
        << "    <soap:Fault>\n"
        << "      <soap:Code>\n"
        << "        <soap:Value>" << EscapeXml(faultCode) << "</soap:Value>\n"
        << "      </soap:Code>\n"
        << "      <soap:Reason>\n"
        << "        <soap:Text xml:lang=\"en\">" << EscapeXml(faultString) << "</soap:Text>\n"
        << "      </soap:Reason>\n";
    
    if (!detail.empty()) {
        oss << "      <soap:Detail>" << EscapeXml(detail) << "</soap:Detail>\n";
    }
    
    oss << "    </soap:Fault>\n"
        << "  </soap:Body>\n"
        << "</soap:Envelope>\n";
    
    return oss.str();
}

bool SoapMessageParser::ValidateWSSecurity(const SoapMessage& message,
                                          const std::string& expectedUser,
                                          const std::string& expectedPass) const {
    if (!message.hasWSSecurity) {
        return false;
    }
    
    return (message.username == expectedUser && message.password == expectedPass);
}

std::string SoapMessageParser::ParseSoapHeader(const std::string& soapXml) const {
    std::regex headerRegex(R"(<soap:Header[^>]*>(.*?)</soap:Header>)", 
                          std::regex_constants::icase | std::regex_constants::ECMAScript);
    std::smatch match;
    
    if (std::regex_search(soapXml, match, headerRegex)) {
        return match[1].str();
    }
    
    return "";
}

std::string SoapMessageParser::ParseSoapBody(const std::string& soapXml) const {
    std::regex bodyRegex(R"(<soap:Body[^>]*>(.*?)</soap:Body>)", 
                         std::regex_constants::icase | std::regex_constants::ECMAScript);
    std::smatch match;
    
    if (std::regex_search(soapXml, match, bodyRegex)) {
        return match[1].str();
    }
    
    return "";
}

std::string SoapMessageParser::ExtractSoapAction(const std::string& soapXml) const {
    // 首先尝试从Header中的Action元素提取
    std::regex actionRegex(R"(<[^:]*:Action[^>]*>(.*?)</[^:]*:Action>)", 
                          std::regex_constants::icase);
    std::smatch match;
    
    if (std::regex_search(soapXml, match, actionRegex)) {
        return match[1].str();
    }
    
    // 如果没有找到，尝试从Body中的第一个元素提取
    std::regex bodyElementRegex(R"(<soap:Body[^>]*>\s*<([^>\s]+))", 
                               std::regex_constants::icase);
    if (std::regex_search(soapXml, match, bodyElementRegex)) {
        std::string elementName = match[1].str();
        // 移除命名空间前缀
        size_t colonPos = elementName.find(':');
        if (colonPos != std::string::npos) {
            elementName = elementName.substr(colonPos + 1);
        }
        return elementName;
    }
    
    return "";
}

bool SoapMessageParser::CheckWSSecurity(const std::string& soapXml) const {
    std::regex wsSecurityRegex(R"(<wsse:Security)", std::regex_constants::icase);
    return std::regex_search(soapXml, wsSecurityRegex);
}

std::pair<std::string, std::string> SoapMessageParser::ExtractCredentials(const std::string& soapXml) const {
    std::string username, password;
    
    // 提取用户名
    std::regex usernameRegex(R"(<wsse:Username[^>]*>(.*?)</wsse:Username>)", 
                            std::regex_constants::icase);
    std::smatch match;
    if (std::regex_search(soapXml, match, usernameRegex)) {
        username = match[1].str();
    }
    
    // 提取密码
    std::regex passwordRegex(R"(<wsse:Password[^>]*>(.*?)</wsse:Password>)", 
                            std::regex_constants::icase);
    if (std::regex_search(soapXml, match, passwordRegex)) {
        password = match[1].str();
    }
    
    return std::make_pair(username, password);
}

std::string SoapMessageParser::EscapeXml(const std::string& input) const {
    std::string escaped = input;
    
    // 替换XML特殊字符
    std::string::size_type pos = 0;
    while ((pos = escaped.find('&', pos)) != std::string::npos) {
        escaped.replace(pos, 1, "&amp;");
        pos += 5;
    }
    
    pos = 0;
    while ((pos = escaped.find('<', pos)) != std::string::npos) {
        escaped.replace(pos, 1, "&lt;");
        pos += 4;
    }
    
    pos = 0;
    while ((pos = escaped.find('>', pos)) != std::string::npos) {
        escaped.replace(pos, 1, "&gt;");
        pos += 4;
    }
    
    pos = 0;
    while ((pos = escaped.find('"', pos)) != std::string::npos) {
        escaped.replace(pos, 1, "&quot;");
        pos += 6;
    }
    
    pos = 0;
    while ((pos = escaped.find('\'', pos)) != std::string::npos) {
        escaped.replace(pos, 1, "&apos;");
        pos += 6;
    }
    
    return escaped;
}

std::string SoapMessageParser::GenerateTimestamp() const {
    auto now = std::chrono::system_clock::now();
    auto time_t = std::chrono::system_clock::to_time_t(now);
    
    std::ostringstream oss;
    oss << std::put_time(std::gmtime(&time_t), "%Y-%m-%dT%H:%M:%SZ");
    return oss.str();
}

// SoapDispatcher实现
SoapDispatcher::SoapDispatcher() = default;
SoapDispatcher::~SoapDispatcher() = default;

void SoapDispatcher::RegisterHandler(const std::string& action, 
                                    std::shared_ptr<ISoapHandler> handler) {
    std::lock_guard<std::mutex> lock(handlersMutex_);
    handlers_[action] = handler;
}

void SoapDispatcher::UnregisterHandler(const std::string& action) {
    std::lock_guard<std::mutex> lock(handlersMutex_);
    handlers_.erase(action);
}

std::string SoapDispatcher::ProcessRequest(const std::string& soapXml,
                                         const std::string& remoteAddr) const {
    SoapMessageParser parser;
    
    // 解析SOAP消息
    SoapMessage message = parser.ParseSoapRequest(soapXml);
    
    if (message.action.empty()) {
        return parser.GenerateSoapFault(SoapError::InvalidAction, 
                                       "No SOAP action found");
    }
    
    // 查找处理器
    std::shared_ptr<ISoapHandler> handler;
    {
        std::lock_guard<std::mutex> lock(handlersMutex_);
        auto it = handlers_.find(message.action);
        if (it != handlers_.end()) {
            handler = it->second;
        }
    }
    
    if (!handler) {
        return parser.GenerateSoapFault(SoapError::NotSupported,
                                       "Action not supported: " + message.action);
    }
    
    // 处理请求
    try {
        return handler->HandleRequest(message, remoteAddr);
    } catch (const std::exception& e) {
        return parser.GenerateSoapFault(SoapError::InternalError, e.what());
    }
}

std::string SoapDispatcher::ProcessHttpRequest(const std::string& method,
                                             const std::string& /*path*/,
                                             const std::string& headers,
                                             const std::string& body,
                                             const std::string& remoteAddr) const {
    // 检查HTTP方法
    if (method != "POST") {
        return GenerateHttpError(405, "Method Not Allowed");
    }
    
    // 检查Content-Type
    if (headers.find("application/soap+xml") == std::string::npos &&
        headers.find("text/xml") == std::string::npos) {
        return GenerateHttpError(415, "Unsupported Media Type");
    }
    
    // 处理SOAP请求
    std::string soapResponse = ProcessRequest(body, remoteAddr);
    
    // 生成HTTP响应
    std::ostringstream response;
    response << "HTTP/1.1 200 OK\r\n"
             << "Content-Type: application/soap+xml; charset=utf-8\r\n"
             << "Content-Length: " << soapResponse.length() << "\r\n"
             << "Connection: close\r\n"
             << "\r\n"
             << soapResponse;
    
    return response.str();
}

void SoapDispatcher::SetAuthenticationMode(SecurityMode mode) {
    std::lock_guard<std::mutex> lock(authMutex_);
    authMode_ = mode;
}

void SoapDispatcher::SetCredentials(const std::string& username, 
                                   const std::string& password) {
    std::lock_guard<std::mutex> lock(authMutex_);
    username_ = username;
    password_ = password;
}

bool SoapDispatcher::ValidateAuthentication(const SoapMessage& message) const {
    std::lock_guard<std::mutex> lock(authMutex_);
    
    if (authMode_ == SecurityMode::NONE) {
        return true;
    }
    
    if (authMode_ == SecurityMode::USERNAME_TOKEN) {
        return message.username == username_ && message.password == password_;
    }
    
    return false;
}

std::string SoapDispatcher::GenerateHttpError(int statusCode, 
                                             const std::string& statusText) const {
    std::ostringstream response;
    response << "HTTP/1.1 " << statusCode << " " << statusText << "\r\n"
             << "Content-Type: text/plain\r\n"
             << "Content-Length: " << statusText.length() << "\r\n"
             << "Connection: close\r\n"
             << "\r\n"
             << statusText;
    
    return response.str();
}

} // namespace Onvif
} // namespace El 